package com.shrcl.engineerprocess.domain.impl;

import com.google.common.base.Objects;
import com.shrcl.engineerprocess.domain.ActorsDAO;
import com.shrcl.engineerprocess.domain.Certification;
import com.shrcl.engineerprocess.domain.CertificationAgencyCode;
import com.shrcl.engineerprocess.domain.CertificationMaintainerByAgency;
import com.shrcl.engineerprocess.domain.CertificationMaintainerByAgencyDAO;
import com.shrcl.engineerprocess.domain.CertificationNotification;
import com.shrcl.engineerprocess.domain.CertificationNotificationDAO;
import com.shrcl.engineerprocess.domain.Engineer;
import com.shrcl.engineerprocess.domain.EngineerCertification;
import com.shrcl.engineerprocess.domain.EngineerCertificationDocument;
import com.shrcl.engineerprocess.domain.EngineerCertificationStatus;
import com.shrcl.engineerprocess.domain.UpdateEngineerCertificationTask;
import com.shrcl.engineerprocess.domain.impl.CertificationImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerCertificationDocumentImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerImpl;
import com.shrcl.engineerprocess.domain.impl.UpdateEngineerCertificationTaskImpl;
import com.shrcl.engineerprocess.domain.proxy.EngineerCertificationProxy;
import com.shrct.businessprocess.organization.RCEmployee;
import com.uniquesoft.uidl.validation.Validates;
import edu.fudan.langlab.domain.document.IDocument;
import edu.fudan.langlab.domain.statemachine.ModelObjectLogService;
import edu.fudan.langlab.domain.task.TSKTask;
import edu.fudan.langlab.domain.task.TSKTaskDAO;
import edu.fudan.langlab.domain.task.TSKTaskOwner;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IObjectFactory;
import edu.fudan.mylang.pf.ISystemDateTimeService;
import edu.fudan.mylang.utils.DateUtil;
import java.util.Collection;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.InputOutput;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;
import org.springframework.beans.factory.BeanFactory;

@Entity
@DiscriminatorValue("ENGINEERCERTIFICATION_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "engineercertification")
public class EngineerCertificationImpl extends BaseModelObject implements EngineerCertification {
  public EngineerCertificationImpl() {
    super();
  }
  
  public EngineerCertificationImpl(final Engineer engineer) {
    super();
    this.engineer = engineer;
  }
  
  private EngineerCertificationStatus Status;
  
  public EngineerCertificationStatus getStatus() {
    return this.Status;
  }
  
  private ModelObjectLogService getModelObjectLogService() {
    return getBeanFactory().getBean(ModelObjectLogService.class);
  }
  
  private void _start() {
    
    Status=EngineerCertificationStatus.created;
  }
  
  public void start() {
    if(Status==null){
    	_start();
    	getModelObjectLogService().createLog(this,"Status","Start");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerCertificationEventsManager.class).fireStarted(this);					
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("allready started");
    }
  }
  
  private void _update(final Procedure1<? super EngineerCertification> updater) {
    
    updater.apply(this);
  }
  
  public void update(final Procedure1<? super EngineerCertification> updater) {
    if(Status==EngineerCertificationStatus.created){
    	_update(updater);
    	getModelObjectLogService().createLog(this,"Status","update");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerCertificationEventsManager.class).fireUpdate(this,updater);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _commit() {
    
    this.checkValid();
    boolean _and = false;
    boolean _notEquals = (!Objects.equal(this.derivedCerf, null));
    if (!_notEquals) {
      _and = false;
    } else {
      EngineerCertificationStatus _status = this.derivedCerf.getStatus();
      String _name = _status.name();
      boolean _equals = _name.equals("closed");
      boolean _not = (!_equals);
      _and = (_notEquals && _not);
    }
    if (_and) {
      this.derivedCerf.forceClosed();
    }
    Status=EngineerCertificationStatus.effective;
  }
  
  public void commit() {
    if(Status==EngineerCertificationStatus.created){
    	_commit();
    	getModelObjectLogService().createLog(this,"Status","commit");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerCertificationEventsManager.class).fireCommit(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _checkTimer() {
    
    BeanFactory _beanFactory = this.getBeanFactory();
    final ISystemDateTimeService dateTimeService = _beanFactory.<ISystemDateTimeService>getBean(ISystemDateTimeService.class);
    boolean _and = false;
    Date _expiredDate = this.getExpiredDate();
    boolean _notEquals = (!Objects.equal(_expiredDate, null));
    if (!_notEquals) {
      _and = false;
    } else {
      Date _expiredDate_1 = this.getExpiredDate();
      Date _day = dateTimeService.today();
      Date _addMonths = DateUtil.addMonths(_day, 3);
      boolean _lessThan = (_expiredDate_1.compareTo(_addMonths) < 0);
      _and = (_notEquals && _lessThan);
    }
    if (_and) {
      InputOutput.<String>println("createUpdateCertificationTask");
      this.createUpdateCertificationNotificationTask();
      this.sendCertificationNotification();
      Status=EngineerCertificationStatus.abouttoexpired;
    }
  }
  
  public void checkTimer() {
    if(Status==EngineerCertificationStatus.effective){
    	_checkTimer();
    	getModelObjectLogService().createLog(this,"Status","checkTimer");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerCertificationEventsManager.class).fireCheckTimer(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _checkExpiredTimer() {
    
    BeanFactory _beanFactory = this.getBeanFactory();
    final ISystemDateTimeService dateTimeService = _beanFactory.<ISystemDateTimeService>getBean(ISystemDateTimeService.class);
    Date _expiredDate = this.getExpiredDate();
    Date _day = dateTimeService.today();
    boolean _lessThan = (_expiredDate.compareTo(_day) < 0);
    if (_lessThan) {
      Status=EngineerCertificationStatus.expired;
    }
  }
  
  public void checkExpiredTimer() {
    if(Status==EngineerCertificationStatus.abouttoexpired||Status==EngineerCertificationStatus.effective){
    	_checkExpiredTimer();
    	getModelObjectLogService().createLog(this,"Status","checkExpiredTimer");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerCertificationEventsManager.class).fireCheckExpiredTimer(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _renew() {
    
    this.createUpdateCertificationNotificationTask();
  }
  
  public void renew() {
    if(Status==EngineerCertificationStatus.expired||Status==EngineerCertificationStatus.effective){
    	_renew();
    	getModelObjectLogService().createLog(this,"Status","renew");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerCertificationEventsManager.class).fireRenew(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _forceClosed() {
    
    Status=EngineerCertificationStatus.closed;
  }
  
  public void forceClosed() {
    if(Status==EngineerCertificationStatus.expired||Status==EngineerCertificationStatus.abouttoexpired||Status==EngineerCertificationStatus.effective){
    	_forceClosed();
    	getModelObjectLogService().createLog(this,"Status","forceClosed");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerCertificationEventsManager.class).fireForceClosed(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  public Boolean isCreated() {
    return com.shrcl.engineerprocess.domain.EngineerCertificationStatus.created==Status;
  }
  
  public Boolean isEffective() {
    return com.shrcl.engineerprocess.domain.EngineerCertificationStatus.effective==Status;
  }
  
  public Boolean isAbouttoexpired() {
    return com.shrcl.engineerprocess.domain.EngineerCertificationStatus.abouttoexpired==Status;
  }
  
  public Boolean isExpired() {
    return com.shrcl.engineerprocess.domain.EngineerCertificationStatus.expired==Status;
  }
  
  public Boolean isClosed() {
    return com.shrcl.engineerprocess.domain.EngineerCertificationStatus.closed==Status;
  }
  
  @JoinColumn(name = "engineer_id")
  @ManyToOne(targetEntity = EngineerImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private Engineer engineer;
  
  public Engineer getEngineer() {
    return this.engineer;
  }
  
  public EngineerCertification setEngineer(final Engineer engineer) {
    this.engineer = engineer;
    return this;			
    
  }
  
  @JoinColumn(name = "certification_id")
  @ManyToOne(targetEntity = CertificationImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private Certification certification;
  
  public Certification getCertification() {
    return this.certification;
  }
  
  public EngineerCertification setCertification(final Certification certification) {
    this.certification = certification;
    return this;			
    
  }
  
  private Date issueDate;
  
  public Date getIssueDate() {
    return this.issueDate;
  }
  
  public EngineerCertification setIssueDate(final Date issueDate) {
    this.issueDate = issueDate;
    return this;			
    
  }
  
  @JoinColumn(name = "derivedCerf_id")
  @ManyToOne(targetEntity = EngineerCertificationImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private EngineerCertification derivedCerf;
  
  public EngineerCertification getDerivedCerf() {
    return this.derivedCerf;
  }
  
  public EngineerCertification setDerivedCerf(final EngineerCertification derivedCerf) {
    this.derivedCerf = derivedCerf;
    return this;			
    
  }
  
  private String comments;
  
  public String getComments() {
    return this.comments;
  }
  
  public EngineerCertification setComments(final String comments) {
    this.comments = comments;
    return this;			
    
  }
  
  @OneToMany(targetEntity = EngineerCertificationDocumentImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, mappedBy = "engineerCertification")
  private Collection<EngineerCertificationDocument> documents = new java.util.ArrayList<com.shrcl.engineerprocess.domain.EngineerCertificationDocument>();;
  
  public Collection<EngineerCertificationDocument> getDocuments() {
    return this.documents;
  }
  
  public EngineerCertificationDocument createAndAddtoDocuments() {
    getDocuments().size();
    com.shrcl.engineerprocess.domain.EngineerCertificationDocument engineerCertificationDocument = new com.shrcl.engineerprocess.domain.impl.EngineerCertificationDocumentImpl(this);
    getObjectFactory().create(engineerCertificationDocument);
    getDocuments().add(engineerCertificationDocument);
    return engineerCertificationDocument;
    
  }
  
  public EngineerCertificationDocument createAndAddtoDocuments(final Procedure1<EngineerCertificationDocument> updater) {
    getDocuments().size();
    com.shrcl.engineerprocess.domain.EngineerCertificationDocument engineerCertificationDocument = new com.shrcl.engineerprocess.domain.impl.EngineerCertificationDocumentImpl(this);
    getObjectFactory().create(engineerCertificationDocument);
    getDocuments().add(engineerCertificationDocument);
    return engineerCertificationDocument;
    
  }
  
  public EngineerCertification removeAllDocuments() {
    for(EngineerCertificationDocument obj : this.documents){
    	getObjectFactory().delete(obj);
    }
    this.documents.clear();
    return this;	
    
  }
  
  public EngineerCertification removeFromDocuments(final EngineerCertificationDocument engineerCertificationDocument) {
    this.documents.remove(engineerCertificationDocument);
    getObjectFactory().delete(engineerCertificationDocument);
    return this;
    
  }
  
  public IDocument createDocument(final Procedure1<? super IDocument> init) {
    EngineerCertificationDocument _createAndAddtoDocuments = this.createAndAddtoDocuments();
    final Procedure1<EngineerCertificationDocument> _function = new Procedure1<EngineerCertificationDocument>() {
        public void apply(final EngineerCertificationDocument it) {
          init.apply(it);
        }
      };
    EngineerCertificationDocument _doubleArrow = ObjectExtensions.<EngineerCertificationDocument>operator_doubleArrow(_createAndAddtoDocuments, _function);
    return _doubleArrow;
  }
  
  public void removeDocument(final IDocument document) {
    this.removeFromDocuments(((EngineerCertificationDocument) document));
  }
  
  public Date getExpiredDate() {
    Date _xifexpression = null;
    boolean _notEquals = (!Objects.equal(this.issueDate, null));
    if (_notEquals) {
      Integer _validity = this.certification.getValidity();
      int _multiply = ((_validity).intValue() * 12);
      Date _addMonths = DateUtil.addMonths(this.issueDate, _multiply);
      _xifexpression = _addMonths;
    }
    return _xifexpression;
  }
  
  public void checkValid() {
    boolean _notEquals = (!Objects.equal(this.certification, null));
    Validates.Assert(_notEquals, "\u8BC1\u4E66\u4E0D\u80FD\u4E3A\u7A7A");
    boolean _notEquals_1 = (!Objects.equal(this.issueDate, null));
    Validates.Assert(_notEquals_1, "\u53D1\u8BC1\u65E5\u671F\u4E0D\u80FD\u4E3A\u7A7A");
  }
  
  private void createUpdateCertificationNotificationTask() {
    BeanFactory _beanFactory = this.getBeanFactory();
    final TSKTaskDAO taskDAO = _beanFactory.<TSKTaskDAO>getBean(TSKTaskDAO.class);
    BeanFactory _beanFactory_1 = this.getBeanFactory();
    final ActorsDAO actorsDAO = _beanFactory_1.<ActorsDAO>getBean(ActorsDAO.class);
    BeanFactory _beanFactory_2 = this.getBeanFactory();
    final CertificationMaintainerByAgencyDAO maintainerByAgencyDAO = _beanFactory_2.<CertificationMaintainerByAgencyDAO>getBean(CertificationMaintainerByAgencyDAO.class);
    CertificationAgencyCode _agency = this.certification.getAgency();
    CertificationMaintainerByAgency _findorInitMaitainerByAgency = maintainerByAgencyDAO.findorInitMaitainerByAgency(_agency);
    Engineer _maintainer = _findorInitMaitainerByAgency.getMaintainer();
    RCEmployee _employee = _maintainer==null?(RCEmployee)null:_maintainer.getEmployee();
    final TSKTaskOwner tskOwner = actorsDAO.asTSKTaskOwner(_employee);
    boolean _notEquals = (!Objects.equal(tskOwner, null));
    Validates.Assert(_notEquals, "\u8BC1\u4E66\u7EF4\u62A4\u4EBA\u5458\u4E0D\u80FD\u4E3A\u7A7A");
    final Procedure1<TSKTask> _function = new Procedure1<TSKTask>() {
        public void apply(final TSKTask it) {
          Date _now = DateUtil.now();
          it.setGenDate(_now);
          Date _now_1 = DateUtil.now();
          it.setStartTime(_now_1);
          Date _now_2 = DateUtil.now();
          Date _addMonths = DateUtil.addMonths(_now_2, 3);
          it.setDueDate(_addMonths);
          it.start();
          it.startProcess();
        }
      };UpdateEngineerCertificationTask updateEngineerCertificationTask=UpdateEngineerCertificationTaskImpl.create(getObjectFactory());
    final Procedure1<UpdateEngineerCertificationTask> _function_1 = new Procedure1<UpdateEngineerCertificationTask>() {
        public void apply(final UpdateEngineerCertificationTask it) {
          it.setEngineerCertification(EngineerCertificationImpl.this);
          it.addOwner(tskOwner);
        }
      };
    UpdateEngineerCertificationTask _doubleArrow = ObjectExtensions.<UpdateEngineerCertificationTask>operator_doubleArrow(updateEngineerCertificationTask, _function_1);
    taskDAO.createTask(_function, _doubleArrow);
  }
  
  private void sendCertificationNotification() {
    BeanFactory _beanFactory = this.getBeanFactory();
    final CertificationNotificationDAO certificationNotificationDAO = _beanFactory.<CertificationNotificationDAO>getBean(CertificationNotificationDAO.class);
    final Procedure1<CertificationNotification> _function = new Procedure1<CertificationNotification>() {
        public void apply(final CertificationNotification it) {
          it.setEngineerCertification(EngineerCertificationImpl.this);
        }
      };
    CertificationNotification _create = certificationNotificationDAO.create(_function);
    _create.performNotify();
  }
  
  public static EngineerCertification create(final Engineer engineer, final IObjectFactory objectFactory) {
    com.shrcl.engineerprocess.domain.EngineerCertification engineerCertification = new com.shrcl.engineerprocess.domain.impl.EngineerCertificationImpl(
    	engineer
    );
    objectFactory.create(engineerCertification);
    return engineerCertification;			
    
  }
  
  public static EngineerCertification createEngineerCertificationImpl(final Engineer engineer, final IObjectFactory objectFactory, final Procedure1<EngineerCertification> init) {
    com.shrcl.engineerprocess.domain.EngineerCertification engineerCertification = new com.shrcl.engineerprocess.domain.impl.EngineerCertificationImpl(
    	engineer
    );
    objectFactory.create(engineerCertification);
    init.apply(engineerCertification);
    
    return engineerCertification;			
    
  }
  
  public EngineerCertificationProxy toProxy() {
    com.shrcl.engineerprocess.domain.proxy.EngineerCertificationProxy proxy = new com.shrcl.engineerprocess.domain.proxy.EngineerCertificationProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    proxy.setStatus(this.getStatus().name());
    return proxy;
    
  }
}
